package com.xlh.enums.courseTest;

import com.alibaba.fastjson.JSONArray;
import com.google.common.collect.Lists;
import com.xlh.dto.courseTest.AnswerSheetDTO;
import com.xlh.dto.courseTest.QuestionTypeDTO;
import com.xlh.exception.common.GlobalException;
import com.xlh.param.courseTest.QuestionAnswerParam;
import com.xlh.pojo.courseTest.CourseQuestionRepositoryDetails;
import com.xlh.pojo.courseTest.CourseTestPaperAnswer;
import com.xlh.pojo.courseTest.CourseTestPaperQuestion;
import com.youbenzi.md2.util.MDUtil;
import lombok.AllArgsConstructor;
import lombok.Getter;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;

import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * @author zhr 2019/1/17
 */
@Getter
@AllArgsConstructor
public enum QuestionTypeEnum {
    CHOICE(1, "选择题") {
        @Override
        public List<CourseQuestionRepositoryDetails> setObject(Map<String, Object> map, Long questionId) {
            List<CourseQuestionRepositoryDetails> list = Lists.newArrayList();
            if (map.get("choice") == null) {
                throw new GlobalException("请检查选择题选项是否正确填写");
            }
            String[] choices = map.get("choice").toString().split("#");
            List<Integer> rightAnswers = formatAnswers(map.get("answer").toString());

            for (int i = 0; i < choices.length; i++) {
                if (StringUtils.isBlank(choices[i])) {
                    throw new GlobalException("选项格式不正确,请检查文件后重新导入");
                }
                CourseQuestionRepositoryDetails details = new CourseQuestionRepositoryDetails();
                details.setQuestionId(questionId);
                details.setOrderNumber(i);
                // 去掉首个字符（选项编号）
                details.setMdContent(choices[i].substring(1));
                details.setHtmlContent(MDUtil.markdown2Html(details.getMdContent()));
                details.setIsCorrect(rightAnswers.contains(i));
                list.add(details);
            }
            return list;
        }

        @Override
        public void checkPractice(AnswerSheetDTO dto, List<CourseQuestionRepositoryDetails> questionAnswerList) {
            List<Integer> rightAnswers = questionAnswerList.stream()
                    .filter(CourseQuestionRepositoryDetails::getIsCorrect)
                    .map(CourseQuestionRepositoryDetails::getOrderNumber)
                    .collect(Collectors.toList());
            boolean right;
            if (rightAnswers.size() == 1) {
                right = Objects.equals(rightAnswers.get(0), dto.getAnswer());
            } else {
                List<Integer> userAnswers = JSONArray.parseArray(JSONArray.toJSONString(dto.getAnswer()), Integer.TYPE);
                right = CollectionUtils.isNotEmpty(userAnswers) && CollectionUtils.isEqualCollection(rightAnswers, userAnswers);
            }
            dto.setRight(right);
        }

        @Override
        public void checkPaper(AnswerSheetDTO dto, List<CourseTestPaperAnswer> questionAnswerList, CourseTestPaperQuestion question) {
            List<Integer> rightAnswers = questionAnswerList.stream()
                    .filter(CourseTestPaperAnswer::getIsCorrect)
                    .map(CourseTestPaperAnswer::getOrderNumber)
                    .collect(Collectors.toList());
            boolean right;
            if (rightAnswers.size() == 1) {
                right = Objects.equals(rightAnswers.get(0), dto.getAnswer());
            } else {
                List<Integer> userAnswers = JSONArray.parseArray(JSONArray.toJSONString(dto.getAnswer()), Integer.TYPE);
                right = CollectionUtils.isNotEmpty(userAnswers) && CollectionUtils.isEqualCollection(rightAnswers, userAnswers);
            }
            dto.setRight(right);
            dto.setScore(right ? question.getScore() : 0);
        }

        @Override
        public String getRightPracticeAnswer(List<CourseQuestionRepositoryDetails> answerList) {
            if (CollectionUtils.isNotEmpty(answerList)) {
                List<Integer> orderNumberList = answerList.stream().filter(CourseQuestionRepositoryDetails::getIsCorrect)
                        .map(CourseQuestionRepositoryDetails::getOrderNumber)
                        .collect(Collectors.toList());
                byte[] bytes = new byte[orderNumberList.size()];
                for (int i = 0; i < orderNumberList.size(); i++) {
                    bytes[i] = (byte) (orderNumberList.get(i) + 65);
                }
                return new String(bytes);
            }
            return "";
        }

        @Override
        public void checkQuestionAnswer(List<QuestionAnswerParam> answer) {
            if (CollectionUtils.isEmpty(answer) || answer.size() < 2) {
                throw new GlobalException("请填写至少两个选项");
            }

            Boolean containRightAnswer = answer.stream().map(QuestionAnswerParam::getIsCorrect).reduce(false, (a, b) -> a || b);
            if (!containRightAnswer) {
                throw new GlobalException("请选择至少一个正确答案");
            }

            answer.forEach(param -> {
                if (param.getContent() == null || param.getHtmlContent() == null) {
                    throw new GlobalException("题目选项不能为空");
                }
            });
        }

        private List<Integer> formatAnswers(String answer) {
            List<Integer> list = Lists.newArrayList();
            char[] answerArray = answer.toCharArray();
            for (char answerChar : answerArray) {
                // 大写字母转为从零开始的索引号
                list.add(answerChar - 65);
            }
            return list;
        }
    },
    JUDGEMENT(2, "判断题") {
        @Override
        public List<CourseQuestionRepositoryDetails> setObject(Map<String, Object> map, Long questionId) {
            CourseQuestionRepositoryDetails details = new CourseQuestionRepositoryDetails();
            details.setQuestionId(questionId);
            details.setOrderNumber(0);
            JudgementEnum judgementEnum = JudgementEnum.forMessage(map.get("answer").toString());
            if (judgementEnum == null) throw new GlobalException("无法识别判断题答案");
            details.setIsCorrect(judgementEnum.getFlag());
            return Lists.newArrayList(details);
        }

        @Override
        public void checkPractice(AnswerSheetDTO dto, List<CourseQuestionRepositoryDetails> questionAnswerList) {
            dto.setRight(Objects.equals(questionAnswerList.get(0).getIsCorrect(), dto.getAnswer()));
        }

        @Override
        public void checkPaper(AnswerSheetDTO dto, List<CourseTestPaperAnswer> questionAnswerList, CourseTestPaperQuestion question) {
            dto.setRight(Objects.equals(questionAnswerList.get(0).getIsCorrect(), dto.getAnswer()));
            dto.setScore(dto.getRight() ? question.getScore() : 0);
        }

        @Override
        public String getRightPracticeAnswer(List<CourseQuestionRepositoryDetails> answerList) {
            if (CollectionUtils.isNotEmpty(answerList)) {
                return answerList.get(0).getIsCorrect() ? "正确" : "错误";
            }
            return "错误";
        }

        @Override
        public void checkQuestionAnswer(List<QuestionAnswerParam> answer) {
            if (CollectionUtils.isEmpty(answer) || answer.get(0).getIsCorrect() == null) {
                throw new GlobalException("请填写题干正确错误信息");
            }
        }
    },
    BLANK(3, "填空题") {
        @Override
        public List<CourseQuestionRepositoryDetails> setObject(Map<String, Object> map, Long questionId) {
            return commonSetObjects(map, questionId);
        }

        @Override
        public void checkPaper(AnswerSheetDTO dto, List<CourseTestPaperAnswer> questionAnswerList, CourseTestPaperQuestion question) {
            throw new UnsupportedOperationException();
        }

        @Override
        public void checkPractice(AnswerSheetDTO dto, List<CourseQuestionRepositoryDetails> questionAnswerList) {
            dto.setRight(Objects.equals(questionAnswerList.get(0).getMdContent(), dto.getAnswer()));

            throw new UnsupportedOperationException();
        }

        @Override
        public String getRightPracticeAnswer(List<CourseQuestionRepositoryDetails> answerList) {
            if (CollectionUtils.isNotEmpty(answerList)) {
                return answerList.get(0).getContent();
            }
            return "";
        }

        @Override
        public void checkQuestionAnswer(List<QuestionAnswerParam> answer) {
            if (CollectionUtils.isEmpty(answer) || answer.get(0).getContent() == null || answer.get(0).getHtmlContent() == null) {
                throw new GlobalException("请填写答案描述");
            }
        }
    },
    SAQ(4, "简答题") {
        @Override
        public List<CourseQuestionRepositoryDetails> setObject(Map<String, Object> map, Long questionId) {
            return commonSetObjects(map, questionId);
        }

        @Override
        public void checkPractice(AnswerSheetDTO dto, List<CourseQuestionRepositoryDetails> questionAnswerList) {
            throw new UnsupportedOperationException();
        }

        @Override
        public void checkPaper(AnswerSheetDTO dto, List<CourseTestPaperAnswer> questionAnswerList, CourseTestPaperQuestion question) {
            throw new UnsupportedOperationException();
        }

        @Override
        public String getRightPracticeAnswer(List<CourseQuestionRepositoryDetails> answerList) {
            if (CollectionUtils.isNotEmpty(answerList)) {
                return answerList.get(0).getContent();
            }
            return "";
        }

        @Override
        public void checkQuestionAnswer(List<QuestionAnswerParam> answer) {
            if (CollectionUtils.isEmpty(answer) || answer.get(0).getContent() == null || answer.get(0).getHtmlContent() == null) {
                throw new GlobalException("请填写答案描述");
            }
        }
    },
    //    PROGRAMMING(5, "编程题") {
//        @Override
//        public List<CourseQuestionRepositoryDetails> setObject(QuestionExcelDataDTO dto, Long questionId, Long maxAnswerId) {
//            return commonSetObjects(dto, questionId, maxAnswerId);
//        }
//    },
    EXPERIMENT(6, "实验题") {
        @Override
        public List<CourseQuestionRepositoryDetails> setObject(Map<String, Object> map, Long questionId) {
            return commonSetObjects(map, questionId);
        }

        @Override
        public void checkPractice(AnswerSheetDTO dto, List<CourseQuestionRepositoryDetails> questionAnswerList) {
            throw new UnsupportedOperationException();
        }

        @Override
        public void checkPaper(AnswerSheetDTO dto, List<CourseTestPaperAnswer> questionAnswerList, CourseTestPaperQuestion question) {
            throw new UnsupportedOperationException();
        }

        @Override
        public Object getRightPracticeAnswer(List<CourseQuestionRepositoryDetails> answerList) {
            throw new UnsupportedOperationException();
        }

        @Override
        public void checkQuestionAnswer(List<QuestionAnswerParam> answer) {
            if (CollectionUtils.isEmpty(answer) || answer.get(0).getContent() == null || answer.get(0).getHtmlContent() == null) {
                throw new GlobalException("请填写答案描述");
            }
        }

    },
    ENCLOSURE(7, "附件题") {
        @Override
        public List<CourseQuestionRepositoryDetails> setObject(Map<String, Object> map, Long questionId) {
            return null;
        }

        @Override
        public void checkPractice(AnswerSheetDTO dto, List<CourseQuestionRepositoryDetails> questionAnswerList) {

        }

        @Override
        public void checkPaper(AnswerSheetDTO dto, List<CourseTestPaperAnswer> questionAnswerList, CourseTestPaperQuestion question) {

        }

        @Override
        public Object getRightPracticeAnswer(List<CourseQuestionRepositoryDetails> answerList) {
            return null;
        }

        @Override
        public void checkQuestionAnswer(List<QuestionAnswerParam> answer) {

        }
    };

    private final Integer code;
    private final String message;

    public abstract List<CourseQuestionRepositoryDetails> setObject(Map<String, Object> map, Long questionId);

    List<CourseQuestionRepositoryDetails> commonSetObjects(Map<String, Object> map, Long questionId) {
        CourseQuestionRepositoryDetails details = new CourseQuestionRepositoryDetails();
        details.setQuestionId(questionId);
        details.setOrderNumber(0);
        details.setMdContent(map.get("answer").toString().replace("*", "\\*"));
        details.setHtmlContent(MDUtil.markdown2Html(details.getMdContent()));
        details.setIsCorrect(true);
        return Lists.newArrayList(details);
    }

    public static QuestionTypeEnum forCode(Integer code) {
        for (QuestionTypeEnum en : QuestionTypeEnum.values()) {
            if (en.code.equals(code)) {
                return en;
            }
        }
        return null;
    }

    public static QuestionTypeEnum forMessage(String message) {
        for (QuestionTypeEnum en : QuestionTypeEnum.values()) {
            if (en.message.equals(message)) {
                return en;
            }
        }
        return null;
    }

    public static List<QuestionTypeDTO> getQuestionTypeList(Integer businessType) {
        List<QuestionTypeDTO> list = Lists.newArrayList();
        for (QuestionTypeEnum en : QuestionTypeEnum.values()) {
            if (businessType.equals(QuestionBusinessTypeEnum.PRACTICE.getCode())) {
                // TODO 以后加入编程题的时候需要改动这里
                if (!en.equals(EXPERIMENT)) {
                    list.add(QuestionTypeDTO.create(en.code, en.message));
                }
            } else {
                if(en.code == 7){ // 屏蔽附件题
                    continue;
                }
                list.add(QuestionTypeDTO.create(en.code, en.message));
            }
        }
        return list;
    }
    public static boolean isObjectiveOther(Integer type) {
        return isChoice(type) || isJudgement(type);
    }

    public static boolean isObjective(Integer type) {
        return isChoice(type) || isJudgement(type) || isBlank(type);
    }

    public static boolean isChoice(Integer type) {
        return CHOICE.getCode().equals(type);
    }

    public static boolean isJudgement(Integer type) {
        return JUDGEMENT.getCode().equals(type);
    }
    public static boolean isBlank(Integer type) {
        return BLANK.getCode().equals(type);
    }
    public static boolean isExperiment(Integer type) {
        return EXPERIMENT.getCode().equals(type);
    }

    public static boolean isSAQ(Integer type) {
        return SAQ.getCode().equals(type);
    }

    public abstract void checkPractice(AnswerSheetDTO dto, List<CourseQuestionRepositoryDetails> questionAnswerList);

    public abstract void checkPaper(AnswerSheetDTO dto, List<CourseTestPaperAnswer> questionAnswerList, CourseTestPaperQuestion question);

    public abstract Object getRightPracticeAnswer(List<CourseQuestionRepositoryDetails> answerList);

    public abstract void checkQuestionAnswer(List<QuestionAnswerParam> answer);
}
